				
                                   
                             - D I S I D E N T S - H A C K  J O U R N A L -

                                               Numero 2
                                                  VI








                                     -+*= Disidents Argentina =*+-

					  Ingenieria Inversa
					  ------------------

			      Ejemplo, Encriptacion, y Dirty Cracking (DC)					


					        By SparK



-------------------------------------------------------------------------------------------------
------------[ INDICE ]---------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------
----[0x00  Como saber si la victima esta encriptada o no ?                                     - 
----[0x01 Analisis                                                                              -
----[0x02 Dirty Cracking                                                                        -
----[0x03 La macabra transparencia del NOP                                                      -
----[0x04 Como modificar un recurso en un archivo EXE ?                                        -  
----[0x05 Programa ejemplo que parchea el Crackme                                               -
----[0x06 Notas Finales                                                                         -
-------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------


Hola a todos, aqui estoy de nuevo con otro articulo de Ingenieria Inversa para que se deleiten :)
En este caso tendremos una victima mas dificil de dominar, es un crack que cuando lo baje de la
pagina del team area54cracks, no tenia solucion todavia, y es del mes de diciembre del 2000!, asi
que miren si sera dificil :)

Veamos el principio de este archivo, la cabecera que nos muestra W32dasm sobre el archivo, es lo
que puede delatar varias caracteristicas del archivo; en nuestro caso nos dira que el archivo
esta encriptado.

El nombre de la victima es: CRACKAME04.EXE
Autor: Henry




-------------------------------------------------------------------------------------------------
------------------[0x00  Como saber si la victima esta encriptada o no ? ]----------------------
-------------------------------------------------------------------------------------------------

En primer lugar analizaremos un archivo sin encriptar y luego, analizaremos la victima y veremos
las diferencias obvias ;)

El archivo que analizaremos primero es otro crackme, llamado killme.exe, estehoy no lo
crackearemos, pero sirve para aprender como un archivo sin encriptar esta estructurado:

Disassembly of File: killme.exe				<-----  Nombre del archivo
Code Offset = 00001000, Code Size = 0000D000		<-----  Tamao de la seccion codigo
Data Offset = 0000E000, Data Size = 00001000		<-----  Tamao de la seccion datos

Number of Objects = 0003 (dec), Imagebase = 00400000h

   Object01: .text    RVA: 00001000 Offset: 00001000 Size: 0000D000 Flags: 60000020
   Object02: .data    RVA: 0000E000 Offset: 0000E000 Size: 00001000 Flags: C0000040
   Object03: .rsrc    RVA: 00010000 Offset: 0000F000 Size: 00001000 Flags: 40000040


+++++++++++++++++++ MENU INFORMATION ++++++++++++++++++

        There Are No Menu Resources in This Application

+++++++++++++++++ DIALOG INFORMATION ++++++++++++++++++

        There Are No Dialog Resources in This Application

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules =    1 (decimal)

   Import Module 001: MSVBVM60.DLL  <------ si leyeron el articulo anterior entenderan que esta 

programado en Visual Basic 6.0 ;-)

   Object01: .text    RVA: 00001000 Offset: 00001000 Size: 0000D000 Flags: 60000020

.text : es una seccion del archivo, los archivos exe de windows PE (Portable Executable)
o NE (New Executable), estan divididos en secciones, en esta .text va el codigo del programa
la logica del mismo el algoritmo que compone al programa.

Object02: .data    RVA: 0000E000 Offset: 0000E000 Size: 00001000 Flags: C0000040

.data : aqui van datos del mismo, quizas valores de variables, constantes, etc

Object03: .rsrc    RVA: 00010000 Offset: 0000F000 Size: 00001000 Flags: 40000040

.rsrc : esta es una seccion interesante del programa, aqui vemos todos los componentes del 
programa, por ejemplo los botones, sus nombres, los menus, etc. Desde aqui podemos cambiar 
cualquier nombre, etiqueta, modificar menus. Existen programas como el Resource Hacker que pueden
hacerlo, pero ya aprenderemos a como hacerlo manualmente, sin programas "enlatados" ;)


Un archivo sin encriptar, contiene estas secciones, mas o menos asi, pueden variar el nombre 
por ejemplo de .text a .code pero se sobrentiende que se trata tambien del codigo del programa.
Nos damos cuenta que esta encriptado cuando los nombres de las secciones no coinciden, y hay 
nombres raros en vez de .code o .text.

Por ejemplo:

 Object01: .SHRINK    RVA: 00001000 Offset: 00001000 Size: 0000D000 Flags: 60000020
 Object02: .SHRINK01    RVA: 0000E000 Offset: 0000E000 Size: 00001000 Flags: C0000040
 Object03: .SHRINK02    RVA: 00010000 Offset: 0000F000 Size: 00001000 Flags: 40000040

Aqui vemos que ese nombre no tiene nada que ver con codigo o datos o recursos, si tomamos ese 
nombre y lo buscamos en Internet, vemos que SHRINK es un compresor/encriptor , significa 
simplemente que el archivo esta encriptado con el SHRINK, facil no?
Debemos conocer el nombre de algunos encriptores, por ejemplo UPX, SHRINK, ASPACK, PEPACK, PKLITE.

Las secciones de un archivo EXE pueden ser mas de 3, pero deben tener una coherencia en el nombre
en las mismas, otra cosa que delata a un archivo encriptado es que no posee strings references 
(si no sabes que es, ver articulo de Zen Cracking), porque sucede esto? , simplemente porque el
archivo al estar encriptado, solamente contiene codigo de maquina ilegible, y tambien la rutina
de desencriptacion, por lo tanto la seccion de resources (.rsrc) no esta a la vista del desensam-
blador, por lo que no encuentra ningun string para mostrar.

Siempre estamos hablando de archivos para WINDOWS, nunca de archivos COM o EXE de DOS, ya que 
no sera tan legible como el desensamblado de un archivo para windows, y esto puede hacerles pensar
de que el programa para DOS esta encriptado, y no es asi.

Bueno, ahora veremos la victima:

Disassembly of File: CRACKAME04.EXE
Code Offset = 00000200, Code Size = 00000000
Data Offset = 00000200, Data Size = 00000000

Number of Objects = 0003 (dec), Imagebase = 00400000h

   Object01: CKA0     RVA: 00001000 Offset: 00000200 Size: 00000000 Flags: E0000080
   Object02: CKAM     RVA: 00010000 Offset: 00000200 Size: 00002C00 Flags: E0000040
   Object03: .rsrc    RVA: 00013000 Offset: 00002E00 Size: 00000E00 Flags: C0000040


+++++++++++++++++++ MENU INFORMATION ++++++++++++++++++

        There Are No Menu Resources in This Application

+++++++++++++++++ DIALOG INFORMATION ++++++++++++++++++

        There Are No Dialog Resources in This Application

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules =    0 (decimal)


+++++++++++++++++++ IMPORT MODULE DETAILS +++++++++++++++

+++++++++++++++++++ EXPORTED FUNCTIONS ++++++++++++++++++
Number of Exported Functions = 0000 (decimal)







-------------------------------------------------------------------------------------------------
---------------------------------------[0x01 Analisis ]------------------------------------------
-------------------------------------------------------------------------------------------------

Como pueden ver en:

   Object01: CKA0     RVA: 00001000 Offset: 00000200 Size: 00000000 Flags: E0000080

esa seccion se llama CKA0, ese nombre no nos dice nada, si buscamos por internet algun encriptor
bajo ese nombre, no encontraremos ninguno, ya que no existe. ;)

   Object02: CKAM     RVA: 00010000 Offset: 00000200 Size: 00002C00 Flags: E0000040

En esta seccion sucede lo mismo, ningun encriptor lleva este nombre.... esto es raro, no?

   Object03: .rsrc    RVA: 00013000 Offset: 00002E00 Size: 00000E00 Flags: C0000040

Solamente .rsrc se ha portado bien, y se mantiene como era cuando lo compilaron.
Esto nos demuestra, que el EXE esta Encriptado, pero no tenemos el nombre del encriptor, porque
SE LO HAN CAMBIADO!!!, exactamente, le han cambiado el nombre a las dos secciones del archivo
para que no se vea con que encriptor esta encriptado.

Para eso usaremos ProcDump, una herramienta, tremendamente util, que la pueden conseguir en
la pagina de Karpoff (welcome.to/karpoff).
Esta herramienta, sirve para desencriptar archivos, encriptados, con los encriptores mas conocidos
editar las secciones de los archivos EXE, y demas maravillas.

Una vez que tengan el programa, lo ejecutamos, y hacemos click en el boton, unpack, aqui nos da 
muchisimas opciones, estos son encriptores, tenemos la opcion Unknown, que es cuando no sabemos
con que esta encriptado el archivo, pero no lo usaremos, porque tarda mucho tiempo, y puede no
funcionar.
Asi que probaremos con el mas probable, yo probe con UPX, y tuve suerte ;-D , era ese.

Entonces, tenemos que el crackme esta encriptado con el UPX, el procdump, nos dira donde queremos
guardar el programa desencriptado, luego, listo ya lo tenemos, para destripar. ;)

Bueno, ahora vamos a ver por donde empezamos:

primero, veremos que el tamao del archivo se incremento con respecto al encriptado, eso significa
que el UPX, es un encirptor/compresor,y que ademas estamos por bueno camino...

Disassembly of File: sinprotec.exe
Code Offset = 00000600, Code Size = 0000D5DA
Data Offset = 00000600, Data Size = 0000D5DA

Number of Objects = 0003 (dec), Imagebase = 00400000h

   Object01: CKA0     RVA: 00001000 Offset: 00000600 Size: 0000D5DA Flags: E0000080
   Object02: CKAM     RVA: 00010000 Offset: 0000DC00 Size: 00002AD0 Flags: E0000040
   Object03: .rsrc    RVA: 00013000 Offset: 00010800 Size: 00000CC0 Flags: C0000040


+++++++++++++++++++ MENU INFORMATION ++++++++++++++++++

        There Are No Menu Resources in This Application

+++++++++++++++++ DIALOG INFORMATION ++++++++++++++++++

        There Are No Dialog Resources in This Application

+++++++++++++++++++ IMPORTED FUNCTIONS ++++++++++++++++++
Number of Imported Modules =    1 (decimal)

   Import Module 001: MSVBVM50.DLL

Esto nos dice W32Dasm, por lo que vemos aqui, el crackme esta hecho en Visual Basic 5.0, las
secciones tienen el mismo nombre, pero su tamao cambio, ademas vemos el boton String References
activado, con lo que tenemos los textos para buscar los saltos que nos daran los puntos de 
ruptura del programa.

Si ejecutamos el crackme vemos que nos dice, No Registrado!!!, luego si hacemos click en el boton
acerca de, veremos que dice Version Sin Registrar, con lo que primero atacaremos a este, para
luego hacer el dirty cracking ;)

Si hacemos click en String References, y hacemos doble click en la cadena 'Registrada =)'
nos llevara aca:

* Possible StringData Ref from Data Obj ->"Registrada =)"
                                  |
:0040BAA9 6884524000              push 00405284
:0040BAAE 8B45E0                  mov eax, dword ptr [ebp-20]
:0040BAB1 8B00                    mov eax, dword ptr [eax]
:0040BAB3 FF75E0                  push [ebp-20]
:0040BAB6 FF5054                  call [eax+54]

Si nos movemos mas arriba buscando algun salto que haga que se muestre esa cadena u otra, 
encontramos:


* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040BA68(C)
|
:0040BA82 C745C444C04000          mov [ebp-3C], 0040C044  <----- Esto le dice al programa que
								el boton fue apretado y que 
								debe mostrar la cadena.

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040BA80(U)
|
:0040BA89 8B45C4                  mov eax, dword ptr [ebp-3C]     <---en estas lineas prepara
:0040BA8C 8B00                    mov eax, dword ptr [eax]		los objetos a mostrar
:0040BA8E 8B4DC4                  mov ecx, dword ptr [ebp-3C]		y demas...
:0040BA91 8B09                    mov ecx, dword ptr [ecx]
:0040BA93 8B09                    mov ecx, dword ptr [ecx]
:0040BA95 50                      push eax
:0040BA96 FF9110030000            call dword ptr [ecx+00000310]
:0040BA9C 50                      push eax
:0040BA9D 8D45E4                  lea eax, dword ptr [ebp-1C]
:0040BAA0 50                      push eax

* Reference To: MSVBVM50.__vbaObjSet, Ord:0000h
                                  |
:0040BAA1 E89656FFFF              Call 0040113C
:0040BAA6 8945E0                  mov dword ptr [ebp-20], eax



y si buscamos mas arriba encontraremos:



* Reference To: MSVBVM50.__vbaFreeObj, Ord:0000h
                                  |
:0040BA50 E8DB56FFFF              Call 00401130
:0040BA55 0FBF45D8                movsx eax, word ptr [ebp-28]
:0040BA59 85C0                    test eax, eax
:0040BA5B 0F8489000000            je 0040BAEA               <------Esto es interesante
:0040BA61 833D44C0400000          cmp dword ptr [0040C044], 00000000
:0040BA68 7518                    jne 0040BA82		  <------Esto es interesante
:0040BA6A 6844C04000              push 0040C044
:0040BA6F 68603A4000              push 00403A60

* Reference To: MSVBVM50.__vbaNew2, Ord:0000h
                                  |
:0040BA74 E8AB56FFFF              Call 00401124
:0040BA79 C745C444C04000          mov [ebp-3C], 0040C044
:0040BA80 EB07                    jmp 0040BA89		   <------Esto es interesante


Bueno, aqui podemos ver que, en el desplazamiento 40BA5B , hay un JE, luego compara con lo que
esta en una zona de memoria, con 0 y luego en 40BA68 hace otro salto, si hacemos doble click
en el primer salto, veremos que nos lleva a otro lado, y si vamos mas abajo veremos esto:

:0040BB2A E80D56FFFF              Call 0040113C
:0040BB2F 8945E0                  mov dword ptr [ebp-20], eax

* Possible StringData Ref from Data Obj ->"Sin Registrar!"  <---Cadena mala, fea :)
                                  |
:0040BB32 68A4524000              push 004052A4
:0040BB37 8B45E0                  mov eax, dword ptr [ebp-20]
:0040BB3A 8B00                    mov eax, dword ptr [eax]
:0040BB3C FF75E0                  push [ebp-20]
:0040BB3F FF5054                  call [eax+54]

Esa es la cadena que nos mostraba!!!!, ok quiere decir que ese salto que esta en 40BA5B, nos lleva
a la cadena no deseada, por lo tanto debemos cambiarlo por un JNE o un JMP, en este caso, el salto
esta compilado de esta manera 0F8489000000 , por lo que cambiaremos por el 0F8589000000, o sea 
el 84 por el 85, y listo.





-------------------------------------------------------------------------------------------------
--------------------------------------[0x02 Dirty Cracking ]-------------------------------------
-------------------------------------------------------------------------------------------------

Si hacemos click en el boton salir, nos apareceran, dos ventanas, con un boton OK, en el medio
este tipo de ventanas son llamadas NagScreens y son realmente muy pesadas, estas ventanas son
generadas a traves de una de las funciones API de Windows, Messagebox, existen diferentes
messagebox es comun, messageboxA es para 32 bits, mientras que el anterior es para 16bits...

Bueno, hagamos dirty cracking, supongamos que se levantaron un dia con bronca y no quieren buscar
el salto adecuado y demas cosas, el programa no da una limitacion como para presionarlos a buscar
un mejor metodo, pero aparecen dos ventanas molestas como las de este crackme, entonces que hacer?
Una forma linda y facil, es "matar" , la llamada al Messagebox (MsgBox).

Si hacemos click en strings references y buscamos el texto que nos pone al salir, Gracias... , bla
bla,bla, nos encontraremos en:

* Possible StringData Ref from Data Obj ->"Gracias por usar este shareware..."
                                  |
:00409890 C7459CBC484000          mov [ebp-64], 004048BC
:00409897 C7459408000000          mov [ebp-6C], 00000008
:0040989E 8D5594                  lea edx, dword ptr [ebp-6C]
:004098A1 8D4DD4                  lea ecx, dword ptr [ebp-2C]



observemos algo que aparece mas abajo: 

* Reference To: MSVBVM50.rtcMsgBox, Ord:0000h   <------ MsgBox, o sea esta es una llamada a la
						
funcion messagebox, aqui, la ventanita es mostrada, o sea que utilizaremos la tecnica:




-------------------------------------------------------------------------------------------------
----------------------------[0x03 La macabra transparencia del NOP  ]----------------------------
-------------------------------------------------------------------------------------------------

Ha llegado la hora de explicar que es un NOP y que es NOPear.

NOP es una instruccion del repertorio de instrucciones de ensamblador que si la analizamos nos
dice esto: No OPeration
No hace ninguna operacion, deja que el procesador termine otras tareas, esta instruccion es usada
para que finalicen otros hilos de una aplicacion mientras se esperan datos de otros hilos, para
recibir datos o cosas asi.

El codigo hexadecimal de la operacion NOP es 90, asi que "mataremos" la llamada a la MsgBox, 
de esta manera:

E8 0A 77 FF FF            ORIGINAL

cambiarlo por:

90 90 90 90 90		  PARCHE

Asi que ejecutamos el Hiew o cualquiero otro editor hexadecimal, y vamos al offset que nos dice 
el W32Dasm, donde esta la llamada al MsgBox, yo se las digo de bueno que soy, pero si leyeron
el articulo de zen cracking ya deberian saber de donde sacarla, una pista es W32Dasm.

El offset es: 8EBB

ahora, tenemos la otra ventana que aparece, que empieza con la palabra "Ademas..."
Buscamos en la String References y encontramos una parte 'Adem', podria ser esa, asi que hacemos
doble click y listo, mas abajo veremos:


* Reference To: MSVBVM50.rtcMsgBox, Ord:0000h  

la segunda llamada a la segunda Nag screen, asi que hacemos lo mismo que con la anterior, todo
lo que ocupa la  instruccion, la rellenaremos con 90.

Matamos las llamadas.... sucio no? ;-D

El toque final, es matar el 'No registrado!!!', que aparece en rojo ni bien ejecutamos el programa
como no tengo ganas de matarme buscando el salto, lo que hare sera machacar el texto, cambiandolo
por otro como por ejemplo, 'Registrado!!!!'.







-------------------------------------------------------------------------------------------------
---------------------[0x04 Como modificar un recurso en un archivo EXE ? ]----------------------
-------------------------------------------------------------------------------------------------

Dare un adelanto, de lo que veremos mas adelante, como modificar menus, botones, activarlos, 
desactivarlos, etc.
Esta vez toca machacar un edit box que contiene originalmente el texto "No registrado!!!" por 
"Registrado!!!!"; para eso, debemos buscar con un editor hexadecimal por ejemplo Hiew (yo uso ese)
para encontrar la cadena, cargamos el archivo con el Hiew, apretamos dos veces F4 y luego 
apretamos F7, y ponemos en el campo que dice ASCII: "No registrado!!!" , y exactamente lo 
encontramos en el offset 1280.

El offset se puede sacar porque en el W32Dasm si buscamos el string ese, nos dara una instruccion

PUSH xxxxxxxx 

 xxxxxxxx que es la direccion de memoria en donde se encuentra el string para guardarla en la pila
y luego mostrarla en pantalla.
Asi que si lo encontramos con el Hiew, pasamos a la columna ASCII presionando TAB, y luego 
solamente escribir lo que queremos, pero OJO! debe mantener la misma longitud.

Por Ejemplo:

N o   R e g i s t r  a  d  o  !  !  ! 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Contiene 16 caracteres la cadena, si nosotros lo reemplazamos por un texto de 17 caracteres, el 
programa seguramente se rompera o se trabe, o inclusive Windows deje de funcionar.
Esto sucede porque si nos pasamos del limite, las secciones que comienzan y terminan en una cierta
direccion dentro del archivo se correrian y se mezclarian.

Entonces ponemos algo como:

R e g i s t r a d o  !  !  !  !  !  !
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

Esta cadena corresponde a los valores siguientes en hexadecimal:

52 65 67 69 73 74 72 61 64 6F 21 21 21 21 21 21 

Y listo! ya terminamos el dirty cracking!!! ;-)




-------------------------------------------------------------------------------------------------
------------[0x05 Programa ejemplo que parchea el Crackme ]--------------------------------------
-------------------------------------------------------------------------------------------------


program CRACKAME04;
uses crt;

Const Offset : Array [1..9] Of LongInt = (8EBB, 8F2F, B05B, 1280 );  {estos son los offsets}

Const Data : Array [1..5] Of Byte = (90 90 90 90 90);  {los NOPs para las ventanitas}
Const Data3 : Array [1..16] Of Byte = (52 65 67 69 73 74 72 61 64 6F 21 21 21 21 21 21);
{es la cadena Registrado!!!!!!}

Var Filename: File;
  i,j:integer;
  Readbyte : Byte;
Begin
  Write ('Parche para CRACKAME04 hecho por SparK, 15/9/2001:');  {intro}


  Assign (Filename, 'CRACKAME04.EXE');  {Archivo a crackear}

  {$I-} Reset (Filename, 1); {$I+}      {Abrimos}
  If IOResult = 0 Then Begin
    Write ('OK!'+ #13+ #10+ ' Chequeando el tamao del archivo : ');  
    If FileSize (Filename) = 71168 Then Begin       {71168 es el tamao desencriptado del file}
      Write ('OK!'+ #13+ #10+ ' Crackeando : ');
     for j:=1 to 2 do 				{lo repetimos dos veces porque son 2 ventanas}
     begin
        Seek (Filename, offset[j] );		{pero las ventanas estan en distintos offsets}
        for i:=1 to 5 do			{vamos poniendo  los 5 NOPs}
           BlockWrite (Filename, Data [i], 1);     {escribimoslos datos en el archivo}
     end;
     Seek (Filename, offset[3] );	{ahora escribimos el byte para la ventana acerca de}
     BlockWrite (Filename, 85, 1);

     Seek (Filename, offset[4] );	{por ultimo la cadena Registrado!!!!!! sobre el file}
        for i:=1 to 16 do
           BlockWrite (Filename, Data3 [i], 1);
     end;
   end;
      Close (Filename);
      WriteLn ('OK!'+ #13+ #10+ 'Archivo Crackeado!!!!');
textcolor(red); writeln ('Disidents Argentina, SparK')
    End Else WriteLn ('EPA!!!'+ #13+ #10+ ' Version Incorrecta');  {esto no creo que suceda ;) }
  End Else WriteLn ('UPS!!!'+ #13+ #10+ ' El archivo no se puede abrir.'); {por si esta en uso}
End.



-------------------------------------------------------------------------------------------------
------------[0x06 Notas Finales ]----------------------------------------------------------------
-------------------------------------------------------------------------------------------------

Bueno, en el ejemplo anterior elegi Pascal, porque si sabes C es facil de interpretar, y sino 
tambien. ;-)
Espero que hayan entendido bastante como funciona esto, mas adelante veremos mas cosas
como por ejemplo, en vez de usar la herramienta ProcDump lo haremo manualmente, etc.


Saludos a todos, espero que les haya gustado


---------------------------------------------------
-       CONTACTA CONMIGO O CON EL TEAM            -
---------------------------------------------------
- NICK:	    Spark                                 -
- CARGO:    Director de Disidents Argentina       -    
- MAIL:     spark@kernel.net             	  -	
- TEAM:     disidents@yahoo.es                    -
---------------------------------------------------




								 
15/09/2001                                                Disidents Argentina  2001 2 edicion. 
------------------------------------------------------------------------------------------------

                     @@-------               @@---------------  
		    @@----                  @@---------       @@@@@@@@@  
		   @@--     @@@@@--        @@-- @@@@@       @     @@  @@@@@@@@@@@@@@@@@@@@@@@@@@@@-------
              @@@@@@    @@ @@      @@ @@@@@@-  @@      @@@ @    @@  @@-----------------------------
             @@        @@ @@@@@   @@ @@---    @@@@@@   @@ @@   @@  @@@@@--------------
            @@        @@     @@  @@ @@ -     @@       @@ @@   @@      @@----------
             @@@@@@@ @@  @@@@@@ @@   @@@@@@@ @@@@@@@ @@  @@ @@	     @@--------
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@------
